package top.jlzhou.tools.http;

import java.io.InputStream;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import top.jlzhou.tools.HttpService;

/**
 * 
 * @ClassName	top.jlzhou.tools.http.HttpServiceByHttpClientImpl
 * @author	J.L.Zhou
 * @date	2019年3月9日 下午5:19:02
 * @version 	V1.0
 * @Copyright	2019 jlzhou.top Inc. All rights reserved. 
 * 	注意：本内容仅限于公司内部传阅，禁止外泄以及用于其他的商业目
 */
@SuppressWarnings("deprecation")
public class HttpServiceByHttpClientImpl implements HttpService {
	

	@Override
	public String send(Request request) throws Exception {
		HttpResponse response = http(request);
		if(response.getStatusLine().getStatusCode()!=200){
			throw new Exception("错误响应状态："+response.getStatusLine().getStatusCode());
		}
		return EntityUtils.toString(response.getEntity(), "UTF-8");
	}

	@Override
	public InputStream download(Request request) throws Exception {
		HttpResponse response = http(request);
		if(response.getStatusLine().getStatusCode()!=200){
			throw new Exception("错误响应状态："+response.getStatusLine().getStatusCode());
		}
		return response.getEntity().getContent();
	}

	public HttpResponse http(Request request) throws Exception {
		HttpClient httpClient = HttpClients.createDefault();
		if (request.getAction().startsWith("https://")) {
			sslClient(httpClient);
		}
		switch (request.getMethod()) {
		case GET:
			HttpGet get = new HttpGet(request.getAction()+getQueryString(request.getParameters()));
			setRequestHeader(get, request.getHeaders());
			return httpClient.execute(get);
		case DELETE:
			HttpDelete delete = new HttpDelete(request.getAction()+getQueryString(request.getParameters()));
			setRequestHeader(delete, request.getHeaders());
			return httpClient.execute(delete);
		case OPTIONS:
			HttpOptions options = new HttpOptions(request.getAction()+getQueryString(request.getParameters()));
			setRequestHeader(options, request.getHeaders());
//			setRequestBody(options, request);
			return httpClient.execute(options);
		case HEAD:
			HttpHead head = new HttpHead(request.getAction()+getQueryString(request.getParameters()));
			setRequestHeader(head, request.getHeaders());
//			setRequestBody(head, request);
			return httpClient.execute(head);
		case PUT:
			HttpPut put = new HttpPut(request.getAction());
			setRequestHeader(put, request.getHeaders());
			setRequestBody(put, request);
			return httpClient.execute(put);
		case TRACE:
			HttpTrace trace = new HttpTrace(request.getAction()+getQueryString(request.getParameters()));
			setRequestHeader(trace, request.getHeaders());
//			setRequestBody(trace, request);
			return httpClient.execute(trace);
		default:
			HttpPost post = new HttpPost(request.getAction());
			setRequestHeader(post, request.getHeaders());
			setRequestBody(post, request);
			return httpClient.execute(post);
		}
	
	}

	@Override
	public void send(Request request, ResponseListener listener) {
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					HttpResponse response = http(request);
					listener.onSuccess(new ResponseByHttpClientImpl(response));
				}catch (Exception e) {
					listener.onError(e);
				}
			}
		}).start();
				
	}
	
	private void sslClient(HttpClient httpClient) {
		try {
			SSLContext ctx = SSLContext.getInstance("TLS");
			X509TrustManager tm = new X509TrustManager() {
				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}

				public void checkClientTrusted(X509Certificate[] xcs, String str) {

				}

				public void checkServerTrusted(X509Certificate[] xcs, String str) {

				}
			};
			ctx.init(null, new TrustManager[] { tm }, null);
			SSLSocketFactory ssf = new SSLSocketFactory(ctx);
			ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			ClientConnectionManager ccm = httpClient.getConnectionManager();
			SchemeRegistry registry = ccm.getSchemeRegistry();
			registry.register(new Scheme("https", 443, ssf));
		} catch (KeyManagementException ex) {
			throw new RuntimeException(ex);
		} catch (NoSuchAlgorithmException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	public String getQueryString(List<Parameter> list) throws Exception{
		if(list==null||list.size()==0){
			return "";
		}
		StringBuffer sb = new StringBuffer();
		for(Parameter p : list){
			sb.append("&");
			sb.append(URLEncoder.encode(p.getName(),"UTF-8"));
			sb.append("=");
			sb.append(URLEncoder.encode(p.getValue(),"UTF-8"));			
		}
		return "?"+sb.substring(1);
	}
	
	public void setRequestBody(HttpEntityEnclosingRequest request,Request r) throws Exception{
		if(request instanceof HttpPost &&r!=null&&r.getFiles()!=null&&r.getFiles().size()>0){
			HttpPost post = (HttpPost)request;
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(600000).setSocketTimeout(600000).build();
			post.setConfig(requestConfig);
			MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
//			multipartEntityBuilder.setCharset(Charset.forName("UT-8"));
//			multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA);
			List<Parameter> list = r.getParameters();
			if(list!=null&&list.size()>0){
				for(Parameter p : list){
					multipartEntityBuilder.addTextBody(p.getName(), p.getValue());
				}
			}
			
			for(MultipartFile f : r.getFiles()){
				multipartEntityBuilder.addBinaryBody(f.getName(), f.getValue());
			}
			
			
		}else{
			List<Parameter> list = r.getParameters();
			if(list==null||list.size()==0){
				return ;
			}
			List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
			for(Parameter p : list){
				nameValuePairList.add(new BasicNameValuePair(p.getValue(),p.getValue()));
			}
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
			formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
			request.setEntity(formEntity);
		}
	}
	
	public void setRequestHeader(HttpMessage request,List<Header> list){
		if(list==null||list.size()==0){
			return ;
		}
		for(Header header : list){
			request.addHeader(header.getName(), header.getValue());
		}
	}

}
